import jwt from 'jsonwebtoken';
import { Forbbiden } from '../code/http-exception';
import User from '../sql/module/user/user';
import Role from '../sql/module/user/role';
import Menu from '../sql/module/menu';
import Application from 'koa';
import { config } from "../config";
import { generateToken } from '../code/util';

const getToken = (ctx: Application.DefaultState) => {
    if (ctx.header && ctx.header.authorization) {
        const parts = ctx.header.authorization.split(' ');
        if (parts.length === 2) {
            //取出token
            const scheme = parts[0];
            const token = parts[1];

            if (/^Bearer$/i.test(scheme)) {
                return token
            } else {
                return false
            }
        }
    }
}
export default (pow: string[] | string) => {
    return async (ctx: Application.DefaultState, next: () => Promise<any>) => {
        if (pow) {
            let timebreak = false
            global.token = ''
            let msg = 'token不合法'
            const token = getToken(ctx)
            if (!token) {
                throw new Forbbiden(msg)
            }
            try {
                jwt.verify(token as string, config.SEC.secretKey)
            } catch (err: any) {
                if (err.name === 'TokenExpiredError') {
                    timebreak = true
                } else {
                    throw new Forbbiden(msg)
                }
            }
            const user = await User.findOne({
                where: {
                    token
                }, include: {
                    model: Role,
                    attributes: {
                        exclude: ['createdAt', 'deletedAt', 'updatedAt']
                    }
                }
            })
            if (!user) {
                msg = '无效令牌'
                throw new Forbbiden(msg)
            }
            const { id, phone, nickname } = user.dataValues
            if (timebreak) {
                global.token = generateToken(nickname)
                await user.update({
                    token: global.token
                })
            }
            const uids: number[] = user.dataValues.Roles.map((item: { uid: any; }) => item.uid)
            if (!uids.includes(100)) {
                if (pow === 'super') {
                    msg = '权限不足'
                    throw new Forbbiden(msg, 400003)
                }
                if (pow !== 'public') {
                    const res = await Role.findAll({ where: { uid: uids }, include: { model: Menu, where: { url: pow } } })
                    if (res.length === 0) {
                        msg = '权限不足'
                        throw new Forbbiden(msg, 400003)
                    }
                }
            }
            ctx.auth = {
                uids,
                scope: phone,
                id,
                name: nickname,
            }
            await next()
        } else {
            await next()
        }
    }
}